package com.googlecode.imule.discovery;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Iterator;

import com.apple.dnssd.DNSRecord;
import com.apple.dnssd.DNSSD;
import com.apple.dnssd.DNSSDException;
import com.apple.dnssd.DNSSDService;
import com.apple.dnssd.QueryListener;
import com.apple.dnssd.ResolveListener;
import com.apple.dnssd.TXTRecord;

/** 
 * Simple data structure to store the contact information. 
 * 
 * Allows the automatic retrieval of the status of the contact by using TXTRecord, attempting 
 * to find a way to transfer a file of manifest.
 * 
 * @author Graham Williamson
 * @author Neil Cowzer
 */
public class Contact implements ResolveListener, QueryListener{

	/** The service name of the contact. */
	protected String serviceName;

	/** The domain the contact is in. */
	protected String domain;

	/** The type of the contact eg. _xxx._udp. */
	protected String regType;

	/** The network interface the contact is on. */
	protected int ifIndex;

	/** The port the contact is communicating on. */
	protected int port;
	
	/** The IP address of the contact. */
	protected InetAddress ipAddress;
	
	/** The txtRecord of the contact. */
	protected TXTRecord txtRecord;	// could be used to status
	
	/* The current status of the contact. */
	private String status;
	
	/* The manifest of the file. */
	private String manifest;
	
	/**
	 * Create a new contact.
	 * 
	 * @param serviceName
	 * @param domain
	 * @param regType
	 * @param ifIndex
	 * @throws DNSSDException
	 */
	public Contact(String serviceName, String domain, String regType, int ifIndex) throws DNSSDException {
		this.serviceName = serviceName;
		this.domain = domain;
		this.regType = regType;
		this.ifIndex = ifIndex;
		this.txtRecord = new TXTRecord();
		this.status = getStatus();
		
		DNSSD.resolve(0, ifIndex, serviceName, regType, domain, this);	// flags == 0; currently ignored
	}
	
	/**
	 * Retrieve the service name of the contact
	 * 
	 * @return the service name
	 */
	public String getServiceName() {
		return serviceName;
	}


	/**
	 * Retrieve the domain of the contact
	 * 
	 * @return the domain
	 */
	public String getDomain() {
		return domain;
	}

	/**
	 * Retrieve the regType of the contact
	 * 
	 * @return the register type
	 */
	public String getRegType() {
		return regType;
	}

	/**
	 * Retrieve the ifIndex of the contact
	 * 
	 * @return the ifIndex
	 */
	public int getIfIndex() {
		return ifIndex;
	}

	/**
	 * Retrieve the port of the contact
	 * 
	 * @return the port
	 */
	public int getPort() {
		return port;
	}

	/**
	 * Retrieve the status of the contact.
	 * 
	 * @return the ipAddress of a system
	 */
	public InetAddress getIpAddress() {
		return ipAddress;
	}

	/**
	 * Retrieve the status of the contact.
	 * 
	 * @return the status of the contact
	 */
	public String getStatus(){
		status = "no status";
		if (txtRecord.contains("status"))
			status = txtRecord.getValueAsString("status");
		return status;
	}
	

	/**
	 * 
	 * @return
	 */
	public String getManifest(){
		return manifest;
	}
	
	/**
	 * 
	 * @param manifest
	 */
	public void setManifest(String manifest){
		this.manifest = manifest;
	}

	/**
	 * Callback invoked when the service name has been resolved.
	 * 
	 * @see com.apple.dnssd.ResolveListener#serviceResolved(com.apple.dnssd.DNSSDService, int, int, java.lang.String, java.lang.String, int, com.apple.dnssd.TXTRecord)
	 */
	public void serviceResolved(DNSSDService resolver, int flags, int ifIndex,
			String fullName, String hostName, int port, TXTRecord txtRecord) {
		this.port = port;
		System.out.println(port);
		
		try {
			// Start a record query to obtain IP address from hostname
			if (ipAddress == null)
				DNSSD.queryRecord( 0, ifIndex, hostName, 1 /* Host Address */, 1 /* ns_c_in */, this);
			
			// txt information request
			DNSSD.queryRecord(0, ifIndex, fullName, 16 /* TXTRecord */, 1 /* Internet class*/, this);
			
		} catch (DNSSDException e) {
			System.out.println("Error resolving hostname: " + hostName);
			e.printStackTrace();
		}
		resolver.stop();	// stop the resolver
	
	}

	/**
	 * Callback invoked when the IP address has been resolved.
	 * 
	 * @see com.apple.dnssd.QueryListener#queryAnswered(com.apple.dnssd.DNSSDService, int, int, java.lang.String, int, int, byte[], int)
	 */
	public void queryAnswered(DNSSDService query, int flags, int ifIndex, 
			java.lang.String fullName, int rrtype, int rrclass, byte[] rdata, int ttl) {
		try {
			if (rrtype == 16 /* TXTRecord */){
				txtRecord = new TXTRecord(rdata);
				System.out.println(serviceName + " -> " +getStatus());
			} else {
				ipAddress = InetAddress.getByAddress(rdata);
				System.out.println(ipAddress);
			}
		} catch (UnknownHostException e) {
			System.out.println("Error resolving IP address: " + fullName);
			e.printStackTrace();
		}
	}

	/**
	 * Something went wrong resolving the hostname or IP address...
	 * 
	 * @see com.apple.dnssd.BaseListener#operationFailed(com.apple.dnssd.DNSSDService, int)
	 */
	public void operationFailed(DNSSDService service, int errorCode) {
		System.out.println("Error resolving service " + service.toString() + ". Error code: " + errorCode);
	}

}
